#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : user_service.py
@TIME          : 2025/03/01 16:30:00
@AUTHOR        : chenlip
@VERSION       : 0.1.0
@DESCRIPTION   : 用户服务模块，提供用户注册、登录等功能服务
'''

import re
from datetime import datetime, timezone
from typing import Dict, List, Tuple, Union, Optional
from flask import current_app

from sqlalchemy.exc import SQLAlchemyError

from init_app import sqldb as db
from app.common.utils import Utils as ut
from app.common.id_generator import SnowflakeIdGenerator # 引入自定义雪花ID生成器
from app.models.user import User, UserExtension, UserMeta, UserActionLog
from app.dto.user_dto import UserDTO, UserExtensionDTO, UserMetaDTO, UserActionLogDTO

from app.common.error_codes import ErrorCode
from app.common.logutil import log, log_error
from app.middlewares.error_handler import BusinessError, service_exception


class UserService:
    """用户服务类，提供用户注册、登录等功能"""

    @staticmethod
    def generate_user_id() -> int:
        """
        使用雪花算法生成分布式用户ID
        
        Returns:
            int: 用户ID
        """
        # 创建雪花ID生成器
        # 机器ID范围(0-31): 可以根据实际部署环境分配不同机器ID
        # 创建雪花ID生成器
        MACHINE_ID = current_app.config.get("MACHINE_ID", 0)
        # print(f"获取配置的机器ID: {MACHINE_ID}")
        
        # 使用自定义雪花ID生成器
        id_generator = SnowflakeIdGenerator(machine_id=MACHINE_ID)
        return id_generator.generate()

    @classmethod
    @service_exception
    def register(cls, register_data: Dict) -> Dict:
        """
        用户注册服务
        
        Args:
            register_data: 包含用户注册信息的字典
                {
                    "loginname": "用户名",
                    "password": "密码",
                    "nickname": "昵称",
                    "email": "邮箱",
                    "phone": "手机号",
                }
                
        Returns:
            Dict: 注册结果
        """
            
        # 2. 检查用户名和邮箱是否已存在
        existing_user: User = User.query.filter(
            (User.loginname == register_data.get("loginname")) |
            (User.email == register_data.get("email")) |
            (User.phone == register_data.get("phone"))
        ).first()
        
        if existing_user:
            if existing_user.loginname == register_data.get("loginname"):
                return ErrorCode.error_response("60001", "用户名已存在", existing_user)
            elif existing_user.email == register_data.get("email"):
                return ErrorCode.error_response("60002", "邮箱已注册", existing_user)
            elif existing_user.phone == register_data.get("phone"):
                return ErrorCode.error_response("60003", "手机号已注册", existing_user)
        
        # 3. 生成用户ID
        user_id = cls.generate_user_id()
        # print(f"生成用户ID: {user_id}")
        
        # 4. 准备用户数据
        user_data = {
            "user_id": user_id,
            "loginname": register_data.get("loginname"),
            "password": register_data.get("password"),
            "nickname": register_data.get("nickname"),
            "email": register_data.get("email"),
            "phone": register_data.get("phone")
        }
        
        # 5. 创建用户
        result = UserDTO.create_user(user_data)
        
        if not result["success"]:
            return ErrorCode.error_response("69999", "用户注册失败, 数据库操作失败", result)
        
        # 7. 创建默认收藏夹 (此功能需要在collection_dto中实现)
        # 如果collection_dto模块已实现，可以调用以下代码:
        # from app.dto.collection_dto import CollectionFolderDTO
        # CollectionFolderDTO.create_default_folder(result["user_id"])
        
        # 8. 发送欢迎通知 (此功能需要在notification_dto中实现)
        # 如果notification_dto模块已实现，可以调用以下代码:
        # from app.dto.notification_dto import NotificationDTO
        # NotificationDTO.send_welcome_notification(result["user_id"])
        
        # 9. 创建积分记录 (此功能需要在points_dto中实现)
        # 如果points_dto模块已实现，可以调用以下代码:
        # from app.dto.points_dto import PointsHistoryDTO
        # PointsHistoryDTO.add_points(result["user_id"], 10, "register", None)
        
        return ErrorCode.success_response(result.get("user_id"), "用户注册成功")
        

    @classmethod
    @service_exception
    def login(cls, login_data: Dict) -> Dict | Tuple[Dict, User]:
        """
        用户登录服务
        
        Args:
            login_data: 包含用户登录信息的字典
                {
                    "login_id": "用户名/邮箱/手机号",
                    "password": "密码"
                }
                
        Returns:
            Dict: 登录结果和用户对象, 数据结构参考：
                {
                    "success": True,
                    "message": "登录成功",
                    "code": "10000",
                    "data": {
                        "user_id": 1,
                        "loginname": "用户名",
                        "nickname": "昵称",
                        "email": "邮箱",
                        "phone": "手机号",
                        "birthday": "2025-03-01",
                        "user_sex": "性别",
                        "description": "用户简介",
                        "qq": "QQ号",
                        "avatar": "头像地址",
                        "status": 1,
                        "role": 0,
                        "is_ai_user": 0,
                        "real_name": "真实姓名",
                        "id_card": "身份证号",
                        "security_question": {"question1": "问题1", "answer1": "答案1", ...},
                        "create_time": "2025-03-01 16:30:00",
                        "update_time": "2025-03-01 16:30:00",
                        "extension": {"current_points": "value1", "current_level": "value2", ...},
                        "user_meta": {"group1": {"key1": "value1", "key2": "value2"}, ...}
                    }
                }
        """
        
        # 1. 数据校验
        if not login_data.get("login_id") or not login_data.get("password"):
            return ErrorCode.error_response("60004", "用户名和密码不能为空", None)
        
        # 2. 用户认证, 获取用户基本信息（包括扩展信息）
        result,user = UserDTO.authenticate_user(
            login_data.get("login_id"),
            login_data.get("password")
        )
        
        if not result["success"]:
            return result, None
        
        user_data = result["data"]
        user_id = user_data["user_id"]

        # 3. 获取用户元数据
        meta_result = UserMetaDTO.get_by_user_id(user_id)
        if not meta_result["success"]:
            return ErrorCode.error_response("60010", "获取用户元数据失败", None)

        result["data"]["user_meta"] = meta_result["data"]

        # 4. 更新登录时间
        extension_result = UserExtensionDTO.get_by_user_id(user_id)
        if extension_result["success"]:
            UserExtensionDTO.update_extension(
                user_id,
                {"last_login_time": datetime.now(timezone.utc)}
            )

        result["data"]["extension"] = extension_result["data"]
        
        # TODO:5. 添加每日登录积分 (此功能需要在points_dto中实现)
        # 如果points_dto模块已实现，可以调用以下代码:
        # from app.dto.points_dto import PointsHistoryDTO
        # PointsHistoryDTO.add_daily_signin_points(user_id)

        return result, user

    @classmethod
    @service_exception
    def refresh_token(cls, identity: int) -> Dict:
        """
        刷新JWT令牌
        
        Args:
            identity: 用户ID
            
        Returns:
            Dict: 包含新令牌的结果
        """
        from flask_jwt_extended import create_access_token
        
        # 生成新的访问令牌
        access_token = create_access_token(identity=identity)
        
        return {
            "success": True,
            "access_token": access_token,
            "token_type": "bearer"
        }
            
    
    @classmethod
    @service_exception
    def get_user_profile(cls, user_id: int) -> Dict:
        """
        获取用户个人资料
        
        Args:
            user_id: 用户ID
            
        Returns:
            Dict: 用户个人资料
        """
        # 获取用户基本信息和扩展信息
        user_result = UserDTO.get_user_by_id(user_id, with_extension=True)
        
        if not user_result["success"]:
            return ErrorCode.error_response("60016", "获取用户信息失败", user_result)
        
        # 获取用户元数据
        meta_result = UserMetaDTO.get_by_user_id(user_id)
        
        if meta_result["success"]:
            user_result["data"]["user_meta"] = meta_result["data"]
        else:
            user_result["data"]["user_meta"] = {}
        
        return user_result
    
    @classmethod
    @service_exception
    def update_profile(cls, user_id: int, profile_data: Dict) -> Dict:
        """
        更新用户个人资料, 不含密码, 不含用户元数据, 不含用户头像
        
        Args:
            user_id: 用户ID
            profile_data: 用户资料数据, 数据结构参考：
                {
                    "nickname": "昵称",
                    "email": "邮箱",
                    "phone": "手机号",
                    "qq": "QQ号",
                    "birthday": "2025-03-01",
                    "user_sex": "性别",
                    "description": "用户简介",
                    "privacy_settings": {"field1": 1, "field2": 0, ...},
                }
            
            
        Returns:
            Dict: 更新结果
        """

        # 更新用户基本信息
        user_update_result = UserDTO.update_user(user_id, profile_data)
        
        if not user_update_result["success"]:
            raise BusinessError(user_update_result["message"], code="60005", data=user_update_result)
        
        # 更新用户扩展信息(如果有)
        extension_fields = ["privacy_settings"]
        extension_data = {}
        
        for field in extension_fields:
            if field in profile_data:
                extension_data[field] = profile_data[field]
        
        if extension_data:
            UserExtensionDTO.update_extension(user_id, extension_data)

        return {"success": True, "message": "个人资料更新成功"}
            
        # except Exception as e:
        #     current_app.logger.error(f"更新用户资料异常: {str(e)}")
        #     return {"success": False, "message": f"更新个人资料失败: {str(e)}"}
    
    @classmethod
    def update_avatar(cls, user_id: int, avatar_url: str) -> Dict:
        """
        更新用户头像
        
        Args:
            user_id: 用户ID
            avatar_url: 头像地址
            
        Returns:
            Dict: 更新结果
        """
        
        result = UserDTO.update_user(user_id, {"avatar": avatar_url})
        if not result["success"]:
            raise BusinessError(result["message"], code="60017", data=result)

        return result


    @classmethod
    @service_exception
    def change_password(cls, user_id: int, password_data: Dict) -> Dict:
        """
        修改密码
        
        Args:
            user_id: 用户ID
            password_data: 包含旧密码和新密码的字典
            
        Returns:
            Dict: 修改结果
        """
        
        old_password = password_data.get("old_password")
        new_password = password_data.get("new_password")
        
        result = UserDTO.change_password(user_id, old_password, new_password)
        if not result["success"]:
            raise BusinessError(result["message"], code="60006", data=result)

        return result
    
    @classmethod
    @service_exception
    def deactivate_account(cls, user_id: int, reason: str = None, client_info: Dict = None) -> Dict:
        """
        注销账户
        
        Args:
            user_id: 用户ID
            reason: 注销原因
            client_info: 客户端信息
            
        Returns:
            Dict: 注销结果
        """
        
        # 记录注销账户原因
        if reason:
            UserMetaDTO.set_meta_value(
                user_id,
                "account_settings",
                "deactivation_reason",
                reason
            )
        
        # 执行账户注销
        result = UserDTO.deactivate_user(user_id)
        
        if result["success"]:
            # 记录注销账户行为
            UserActionLogDTO.log_action(
                user_id=user_id,
                action_type=6,  # 假设6表示注销账户行为
                target_type=1,  # 用户自身
                target_id=user_id,
                client_info=client_info
            )
        else:
            raise BusinessError(result["message"], code="60018", data=result)
        
        return result
        
    @classmethod
    @service_exception
    def query_user(cls, query_data: Dict) -> Dict:
        """
        查询用户
        
        Args:
            query_data: 查询条件
                {
                    "page": 1,
                    "per_page": 10,
                    "filters": {"field1": "value1", "field2": "value2", ...},
                    "sort": {"field": "asc/desc"},
                    "fields": ["field1", "field2", ...]
                }
            
        Returns:
            Dict: 查询结果
        """
        
        result = UserDTO.query_users(query_data)
        return result
        
    @classmethod
    @service_exception
    def user_log_action(cls, user_id: int, action_data: Dict) -> Dict:
        """
        记录用户行为
        
        Args:
            user_id: 用户ID
            action_data: 行为数据
                {
                    "action_type": 1,  # 行为类型
                    "target_type": 1,  # 目标类型
                    "target_id": 1,    # 目标ID
                    "client_info": {"ip": "客户端IP", "device": "设备信息", ...}
                }
        Returns:
            Dict: 记录结果
        """
        result = UserActionLogDTO.log_action(
            user_id=user_id,
            action_type=action_data.get("action_type", 1),
            target_type=action_data.get("target_type", 1),
            target_id=action_data.get("target_id", 0),
            client_info=action_data.get("client_info", {})
        )
        return result
        
    @classmethod
    @service_exception
    def get_user_log_action(cls, user_id: int, query_data: Dict) -> Dict:
        """
        获取用户行为记录
        
        Args:
            user_id: 用户ID
            query_data: 查询条件
                {
                    "action_type": 1,
                    "start_time": 2025-03-01 16:30:00,
                    "end_time": 2025-03-02 16:30:00,
                    "limit": 1,
                    "desc": True # 是否创建时间降序排列(从新到旧), 默认True
                }
            
        Returns:
            Dict: 查询结果
        """
        
        result = UserActionLogDTO.get_user_actions(
            user_id, 
            query_data.get("action_type"), 
            query_data.get("start_time", "2025-03-01 16:30:00"), 
            query_data.get("end_time", ut.CURTIME), 
            query_data.get("limit", 10), 
            query_data.get("desc", True)
        )
        return result
